package com.zhuanzhuan.hero.user.aspect;

import com.bj58.youpin.common.rpc.result.Result;
import com.bj58.youpin.common.utils.json.JsonUtils;
import com.bj58.zhuanzhuan.zzentry.common.service.entity.ServiceHeaderEntity;
import com.bj58.zhuanzhuan.zzentry.common.service.entity.ZZOpenScfBaseResult;
import com.zhuanzhuan.hero.biz.common.util.WxWarnTemplateUtil;
import com.zhuanzhuan.hero.user.consts.Consts;
import com.zhuanzhuan.hero.user.enums.ExceptionMsgEnum;
import com.zhuanzhuan.hero.user.exception.BusinessException;
import com.zhuanzhuan.hero.user.util.ValidUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @ClassName GlobalHandlerAop
 * @Description  校验入参和全局捕获异常
 *    要想用参数校验 必须在实现类的方法入参加注解@Valid，接口方法可以不加
 * @Author hanjunjun
 * @Date 2024/6/20 16:59
 */
@Aspect
@Component
@Slf4j
public class GlobalHandlerAop {

    @Around(value = "execution(public * com.zhuanzhuan.hero.user.facade..*.*(..))")
    public Object handler(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Class returnType = signature.getReturnType();

        Method method = signature.getMethod();
        String methodName = method.getName();
        Object[] args = joinPoint.getArgs();

        //打印入参  两个以上的入参封装对象
        log.info("GlobalHandler before method={} param={}", methodName, JsonUtils.toJsonWithoutNull(args));
        
        //参数校验
        try {
            ValidUtil.preValidParams(signature, args);
        } catch (IllegalArgumentException e) {
            log.error("参数校验异常", e);
            return this.buildErrorResponse(returnType, ExceptionMsgEnum.PARAM_ERROR.getCode(), e.getMessage());
        }

        //全局异常处理
        Object result;
        try {
            result = joinPoint.proceed();
        } catch (BusinessException e) {
            log.info("执行业务异常", e);
            result = this.buildErrorResponse(returnType, e.getCode(), e.getMessage());
        } catch (IllegalArgumentException e) {
            log.error("参数异常", e);
            result = this.buildErrorResponse(returnType, ExceptionMsgEnum.PARAM_ERROR.getCode(), e.getMessage());
        } catch (Throwable e) {
            log.error("执行未知异常", e);
            WxWarnTemplateUtil.warnOutService(Consts.SERVICE_NAME, e.getMessage());
            result = this.buildErrorResponse(returnType, ExceptionMsgEnum.COMMON_ERROR.getCode(), ExceptionMsgEnum.COMMON_ERROR.getErrorMsg());
        }
        log.info("GlobalHandler after method={} result={}", methodName, JsonUtils.toJsonWithoutNull(result));
        return result;
    }

    /**
     * 解析出业务参数
     *
     * @param args
     * @return java.lang.Object
     * @author  hanjunjun
     * @date 2024/7/30
     **/
    private Object getBusinessParam(Object[] args) {
        ServiceHeaderEntity header = null;
        for (Object arg : args) {
            if (!(arg instanceof ServiceHeaderEntity)) {
                return arg;
            }
            header = (ServiceHeaderEntity)arg;
        }

        //只有header一个入参  返回uid
        if (Objects.nonNull(header)) {
            return header.getUid();
        }
        return null;
    }

    /**
     * 装配失败返回值
     *   支持ZZOpenScfBaseResult和Result类型
     * @param returnType
     * @param errorCode
     * @param errorMsg
     * @return java.lang.Object
     * @author  hanjunjun
     * @date 2024/6/20
     **/
    private Object buildErrorResponse(Class returnType, Integer errorCode, String errorMsg) {
        Object response;
        if (ZZOpenScfBaseResult.class.equals(returnType)) {
            response = ZZOpenScfBaseResult.buildErr(errorCode, errorMsg);
        } else if (Result.class.equals(returnType)) {
            response = Result.fail(errorCode, errorMsg);
        } else {
            throw new RuntimeException("facade returnType error");
        }

        return response;
    }

}
